# -*- coding: utf-8 -*-
"""
账户管理业务控制器

处理账户余额、充值、消费、交易记录等核心业务逻辑
支持线上支付集成和账户安全验证
"""

from datetime import datetime, timedelta
from decimal import Decimal, ROUND_HALF_UP
from typing import Optional, Dict, List, Tuple, Any
from flask import current_app
from sqlalchemy import and_, or_, desc, func
from sqlalchemy.exc import IntegrityError, SQLAlchemyError

from app import db
from app.models.user import User
from app.models.account import UserAccount, Transaction
from app.models.reservation import Reservation
from app.utils.exceptions import BusinessError, ValidationError


class AccountController:
    """账户管理业务控制器"""

    @staticmethod
    def get_account_summary(user_id: int) -> Dict[str, Any]:
        """
        获取账户概览信息

        Args:
            user_id: 用户ID

        Returns:
            包含账户信息的字典

        Raises:
            BusinessError: 当账户不存在时
        """
        try:
            # 获取用户账户
            account = UserAccount.query.filter_by(user_id=user_id).first()
            if not account:
                # 自动创建账户
                account = AccountController._create_account(user_id)

            # 获取近30天交易统计
            thirty_days_ago = datetime.now() - timedelta(days=30)
            recent_transactions = Transaction.query.filter(
                and_(
                    Transaction.user_id == account.user_id,
                    Transaction.created_at >= thirty_days_ago
                )
            ).all()

            # 计算统计数据
            total_income = sum(
                t.amount for t in recent_transactions
                if t.type in ['recharge', 'refund']
            )
            total_expense = sum(
                abs(t.amount) for t in recent_transactions
                if t.type in ['consume']
            )

            # 获取待处理预约费用
            pending_reservations = Reservation.query.filter(
                and_(
                    Reservation.student_id == user_id,
                    Reservation.status == 'confirmed'
                )
            ).all()

            pending_amount = sum(r.price for r in pending_reservations)

            return {
                'account': account,
                'balance': account.balance,
                'available_balance': account.balance,
                'total_income_30d': total_income,
                'total_expense_30d': total_expense,
                'pending_amount': pending_amount,
                'transaction_count_30d': len(recent_transactions)
            }

        except SQLAlchemyError as e:
            current_app.logger.error(f"获取账户概览失败 - 用户ID: {user_id}, 错误: {str(e)}")
            raise BusinessError("获取账户信息失败，请稍后重试")

    @staticmethod
    def recharge_account(user_id: int, amount: Decimal, payment_method: str,
                        payment_reference: Optional[str] = None,
                        operator_id: Optional[int] = None) -> Dict[str, Any]:
        """
        账户充值

        Args:
            user_id: 用户ID
            amount: 充值金额
            payment_method: 支付方式
            payment_reference: 支付凭证号

        Returns:
            充值结果信息

        Raises:
            ValidationError: 参数验证失败
            BusinessError: 业务逻辑错误
        """
        # 参数验证
        if amount <= 0:
            raise ValidationError("充值金额必须大于0")

        if amount > Decimal('10000'):
            raise ValidationError("单次充值金额不能超过10000元")

        if payment_method not in ['wechat', 'alipay', 'offline', 'cash', 'bank_transfer', 'pos', 'other']:
            raise ValidationError("不支持的支付方式")

        try:
            # 获取或创建账户
            account = UserAccount.query.filter_by(user_id=user_id).first()
            if not account:
                account = AccountController._create_account(user_id)

            # 计算交易后余额
            new_balance = account.balance + amount

            # 创建充值交易记录
            transaction = Transaction(
                user_id=account.user_id,
                type='recharge',
                amount=amount,
                balance_after=new_balance,
                description=f"账户充值 - {payment_method}",
                payment_method=payment_method,
                operator_id=operator_id
            )

            # 更新账户余额和统计
            account.balance = new_balance
            account.total_recharge += amount

            # 保存到数据库
            db.session.add(transaction)
            db.session.commit()

            current_app.logger.info(
                f"账户充值成功 - 用户ID: {user_id}, 金额: {amount}, "
                f"支付方式: {payment_method}, 新余额: {account.balance}"
            )

            return {
                'success': True,
                'transaction_id': transaction.id,
                'new_balance': account.balance,
                'amount': amount,
                'payment_method': payment_method
            }

        except IntegrityError as e:
            db.session.rollback()
            current_app.logger.error(f"充值数据完整性错误 - 用户ID: {user_id}, 错误: {str(e)}")
            raise BusinessError("充值失败，请检查数据完整性")
        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(f"充值数据库错误 - 用户ID: {user_id}, 错误: {str(e)}")
            raise BusinessError("充值失败，请稍后重试")

    @staticmethod
    def consume_balance(user_id: int, amount: Decimal, description: str,
                       reference_type: Optional[str] = None,
                       reference_id: Optional[int] = None) -> Dict[str, Any]:
        """
        消费账户余额

        Args:
            user_id: 用户ID
            amount: 消费金额
            description: 消费描述
            reference_type: 关联类型（如 'reservation'）
            reference_id: 关联ID

        Returns:
            消费结果信息

        Raises:
            ValidationError: 参数验证失败
            BusinessError: 余额不足或其他业务错误
        """
        if amount <= 0:
            raise ValidationError("消费金额必须大于0")

        try:
            # 获取账户
            account = UserAccount.query.filter_by(user_id=user_id).first()
            if not account:
                raise BusinessError("账户不存在")

            # 检查余额是否充足
            if account.balance < amount:
                raise BusinessError(f"余额不足，当前余额: {account.balance}元，需要: {amount}元")

            # 计算交易后余额
            new_balance = account.balance - amount

            # 创建消费交易记录
            transaction = Transaction(
                user_id=account.user_id,
                type='consume',
                amount=-amount,  # 消费为负数
                balance_after=new_balance,
                description=description,
                reservation_id=reference_id if reference_type == 'reservation' else None
            )

            # 更新账户余额和统计
            account.balance = new_balance
            account.total_consumption += amount

            # 保存到数据库
            db.session.add(transaction)
            db.session.commit()

            current_app.logger.info(
                f"账户消费成功 - 用户ID: {user_id}, 金额: {amount}, "
                f"描述: {description}, 新余额: {account.balance}"
            )

            return {
                'success': True,
                'transaction_id': transaction.id,
                'new_balance': account.balance,
                'amount': amount,
                'description': description
            }

        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(f"消费数据库错误 - 用户ID: {user_id}, 错误: {str(e)}")
            raise BusinessError("消费失败，请稍后重试")

    @staticmethod
    def get_transaction_history(user_id: int, page: int = 1, per_page: int = 20,
                              transaction_type: Optional[str] = None,
                              start_date: Optional[datetime] = None,
                              end_date: Optional[datetime] = None) -> Dict[str, Any]:
        """
        获取交易历史记录

        Args:
            user_id: 用户ID
            page: 页码
            per_page: 每页条数
            transaction_type: 交易类型筛选
            start_date: 开始日期
            end_date: 结束日期

        Returns:
            分页的交易记录
        """
        try:
            # 获取账户
            account = UserAccount.query.filter_by(user_id=user_id).first()
            if not account:
                return {
                    'transactions': [],
                    'total': 0,
                    'pages': 0,
                    'current_page': page,
                    'per_page': per_page
                }

            # 构建查询条件
            query = Transaction.query.filter(Transaction.user_id == account.user_id)

            if transaction_type:
                query = query.filter(Transaction.type == transaction_type)

            if start_date:
                query = query.filter(Transaction.created_at >= start_date)

            if end_date:
                query = query.filter(Transaction.created_at <= end_date)

            # 分页查询
            pagination = query.order_by(desc(Transaction.created_at)).paginate(
                page=page, per_page=per_page, error_out=False
            )

            return {
                'transactions': pagination.items,
                'total': pagination.total,
                'pages': pagination.pages,
                'current_page': page,
                'per_page': per_page,
                'has_prev': pagination.has_prev,
                'has_next': pagination.has_next
            }

        except SQLAlchemyError as e:
            current_app.logger.error(f"获取交易历史失败 - 用户ID: {user_id}, 错误: {str(e)}")
            return {
                'transactions': [],
                'total': 0,
                'pages': 0,
                'current_page': page,
                'per_page': per_page
            }

    @staticmethod
    def get_transaction_detail(transaction_id: int, user_id: int) -> Optional[Transaction]:
        """
        获取单个交易的详细信息

        Args:
            transaction_id: 交易ID
            user_id: 用户ID（用于权限验证）

        Returns:
            交易对象，如果不存在或无权限则返回None
        """
        try:
            # 查找交易记录，确保用户只能查看自己的交易
            transaction = Transaction.query.filter(
                and_(
                    Transaction.id == transaction_id,
                    Transaction.user_id == user_id
                )
            ).first()

            return transaction

        except SQLAlchemyError as e:
            current_app.logger.error(f"获取交易详情失败 - 交易ID: {transaction_id}, 用户ID: {user_id}, 错误: {str(e)}")
            return None

    @staticmethod
    def get_consumption_statistics(user_id: int, period: str = 'month') -> Dict[str, Any]:
        """
        获取消费统计信息

        Args:
            user_id: 用户ID
            period: 统计周期 ('week', 'month', 'quarter', 'year')

        Returns:
            消费统计数据
        """
        try:
            # 获取账户
            account = UserAccount.query.filter_by(user_id=user_id).first()
            if not account:
                return {'error': '账户不存在'}

            # 确定时间范围
            now = datetime.now()
            if period == 'week':
                start_date = now - timedelta(days=7)
            elif period == 'month':
                start_date = now - timedelta(days=30)
            elif period == 'quarter':
                start_date = now - timedelta(days=90)
            elif period == 'year':
                start_date = now - timedelta(days=365)
            else:
                start_date = now - timedelta(days=30)

            # 查询交易记录
            transactions = Transaction.query.filter(
                and_(
                    Transaction.user_id == account.user_id,
                    Transaction.created_at >= start_date
                )
            ).all()

            # 统计数据
            stats = {
                'total_transactions': len(transactions),
                'total_income': Decimal('0'),
                'total_expense': Decimal('0'),
                'by_type': {},
                'by_date': {},
                'average_per_transaction': Decimal('0')
            }

            # 按类型统计
            for transaction in transactions:
                t_type = transaction.type
                if t_type not in stats['by_type']:
                    stats['by_type'][t_type] = {
                        'count': 0,
                        'amount': Decimal('0')
                    }

                stats['by_type'][t_type]['count'] += 1
                stats['by_type'][t_type]['amount'] += abs(transaction.amount)

                # 收入支出统计
                if transaction.amount > 0:
                    stats['total_income'] += transaction.amount
                else:
                    stats['total_expense'] += abs(transaction.amount)

                # 按日期统计
                date_key = transaction.created_at.strftime('%Y-%m-%d')
                if date_key not in stats['by_date']:
                    stats['by_date'][date_key] = Decimal('0')
                stats['by_date'][date_key] += abs(transaction.amount)

            # 计算平均值
            if stats['total_transactions'] > 0:
                stats['average_per_transaction'] = (
                    stats['total_expense'] / stats['total_transactions']
                ).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

            return stats

        except SQLAlchemyError as e:
            current_app.logger.error(f"获取消费统计失败 - 用户ID: {user_id}, 错误: {str(e)}")
            return {'error': '获取统计信息失败'}

    @staticmethod
    def refund_transaction(transaction_id: int, reason: str) -> Dict[str, Any]:
        """
        退款处理

        Args:
            transaction_id: 原交易ID
            reason: 退款原因

        Returns:
            退款结果
        """
        try:
            # 查找原交易
            original_transaction = Transaction.query.get(transaction_id)
            if not original_transaction:
                raise BusinessError("交易记录不存在")

            if original_transaction.amount >= 0:
                raise BusinessError("只能退款消费交易")


            # 获取账户
            account = UserAccount.query.filter_by(user_id=original_transaction.user_id).first()

            # 计算交易后余额
            refund_amount = abs(original_transaction.amount)
            new_balance = account.balance + refund_amount

            # 创建退款交易
            refund_transaction = Transaction(
                user_id=account.user_id,
                type='refund',
                amount=refund_amount,
                balance_after=new_balance,
                description=f"退款 - {reason}"
            )

            # 更新账户余额
            account.balance = new_balance

            # 保存到数据库
            db.session.add(refund_transaction)
            db.session.commit()

            current_app.logger.info(
                f"退款成功 - 原交易ID: {transaction_id}, 金额: {refund_amount}, "
                f"账户ID: {account.id}, 原因: {reason}"
            )

            return {
                'success': True,
                'refund_transaction_id': refund_transaction.id,
                'refund_amount': refund_amount,
                'new_balance': account.balance
            }

        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(f"退款失败 - 交易ID: {transaction_id}, 错误: {str(e)}")
            raise BusinessError("退款失败，请稍后重试")

    @staticmethod
    def _create_account(user_id: int) -> UserAccount:
        """
        创建新账户

        Args:
            user_id: 用户ID

        Returns:
            新创建的账户对象
        """
        try:
            account = UserAccount(
                user_id=user_id,
                balance=Decimal('0')
            )

            db.session.add(account)
            db.session.commit()

            current_app.logger.info(f"创建新账户 - 用户ID: {user_id}")
            return account

        except SQLAlchemyError as e:
            db.session.rollback()
            current_app.logger.error(f"创建账户失败 - 用户ID: {user_id}, 错误: {str(e)}")
            raise BusinessError("创建账户失败")

    @staticmethod
    def validate_payment_amount(amount: str) -> Decimal:
        """
        验证并转换支付金额

        Args:
            amount: 金额字符串

        Returns:
            验证后的金额

        Raises:
            ValidationError: 金额格式错误
        """
        try:
            decimal_amount = Decimal(str(amount))

            # 金额必须为正数
            if decimal_amount <= 0:
                raise ValidationError("金额必须大于0")

            # 金额不能超过最大限制
            if decimal_amount > Decimal('100000'):
                raise ValidationError("金额不能超过100000元")

            # 保留两位小数
            return decimal_amount.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

        except (ValueError, TypeError):
            raise ValidationError("金额格式错误")